/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package okio;

import javax.annotation.Nullable;

/**
 * A collection of unused segments, necessary to avoid GC churn and zero-fill.
 * This pool is a thread-safe static singleton.
 */
final class SegmentPool {
  /** The maximum number of bytes to pool. */
  // TODO: Is 64 KiB a good maximum size? Do we ever have that many idle segments?
  static final long MAX_SIZE = 64 * 1024; // 64 KiB.

  /** Singly-linked list of segments. */
  static @Nullable Segment next;

  /** Total bytes in this pool. */
  static long byteCount;

  private SegmentPool() {
  }

  /**take方法用来取数据
     * 如果池子为空就创建一个空对象 owner true | share false
     * next是链表的头 就是一个简单的取表头的操作
     * @return
 	*/
  // 为了防止多线程同时操作造成数据的错乱，这里加了锁，这里的next命名虽然是next，但是实际上是整个对象池的头，但是next为空，表示池子为空，直接返回一个空对象，否则从里面拿出next，并将next的下一个节点赋为next，置一下状态
  static Segment take() {
    synchronized (SegmentPool.class) {
      //result 的 next 没有了, 但是 pre 还是有的..
      if (next != null) {
        Segment result = next;
        next = result.next;
        result.next = null;
        byteCount -= Segment.SIZE;
        return result;
      }
    }
    return new Segment(); // Pool is empty. Don't zero-fill while holding a lock.
  }

  //准备添加到复用中, 数据读取完全靠 pos, limit 控制着.
  //后面被回收的参数会被安排到链表的后面, 其中 next 是第一个参数.
  // 如果要回收的segment有前后引用或者是共享的，就不能被回收，所以要回收前先将引用置空，同样这里也加了锁，以免那个同时回收超过池子最大的大小，然后就是将回收的插到表头的操作。
  // 所以SegmentPool无论是回收和取对象都是在表头操作
  static void recycle(Segment segment) {
    //如果当前要回收的segment有前后引用或者是共享的 那么就回收失败
    if (segment.next != null || segment.prev != null) throw new IllegalArgumentException();
    if (segment.shared) return; // This segment cannot be recycled.
    synchronized (SegmentPool.class) {
      // 如果加入后的大小超过了最大大小 也会失败
      if (byteCount + Segment.SIZE > MAX_SIZE) return; // Pool is full.
      byteCount += Segment.SIZE;
      segment.next = next;
      segment.pos = segment.limit = 0;
      next = segment;
    }
  }
}
